import hashlib
import hmac
import time

import httplib2
import simplejson

import coin.exchange.base.kr_rest.rest_client_base as rcb
from coin.exchange.base.kr_rest.auth_base import AuthKey
from coin.exchange.util.rate_limit import RateLimiter


class CoincheckOrderBase(object):
  def __init__(self, key_file):
    key = AuthKey.from_file(key_file)
    self.access_token = key.access_key
    self.secret_key = key.secret_key_upper_bytes
    self.rate_limit = RateLimiter(3, 1.0)
    self.api_url = 'https://coincheck.com'

  def _nonce(self):
    return str(int(round(time.time() * 1000000)))

  def get_signature(self, request_url, request_body, secret_key):
    nonce = self._nonce()
    message = nonce + request_url + request_body
    signature = hmac.new(secret_key, message, hashlib.sha512)
    return signature.hexdigest(), nonce

  def get_response(self, url, request_body):
    url = self.api_url + "/" + url
    signiture, nonce = self.get_signature(url, request_body, self.secret_key)
    headers = {'ACCESS-NONCE': nonce, 'ACCESS-KEY': encoded_payload, 'ACCESS-SIGNATURE': signiture}
    http = httplib2.Http()
    response, content = http.request(url, 'GET', headers=headers, body=request_body)
    return content

  def _query_nocheck(self, endpoint, params=None):
    req_timestamp = time.time()
    content = self.get_response(endpoint, params)
    res_timestamp = time.time()
    # cannot handle double quote
    # if there is an error message, it will have single quote.
    if "Blocked user access." in content.decode("utf-8") or \
       content == '{"result":"error","errorCode":"4","errorMsg":"Blocked user access."}':
      return rcb.RestUpdate(req_timestamp, res_timestamp, dict(result="error", errorCode="4"))
    content = simplejson.loads(content)
    return rcb.RestUpdate(req_timestamp, res_timestamp, content)

  def _query(self, endpoint, params=None, disable_rate_limit=False):
    if not disable_rate_limit:
      while not self.rate_limit.check():
        time.sleep(0.1)
    else:
      self.rate_limit.check()
    return self._query_nocheck(endpoint, params=params)


class CoincheckNativePrivateClient(CoincheckOrderBase):
  def __init__(self, key_file):
    CoinoneOrderBase.__init__(self, key_file)

  def _assert_success(self, content):
    assert content['success'] == True, content

  def publish_new_order(self, rate, amount, order_type, pair):
    return self._query('/api/exchange/orders',
                       params=dict(rate=rate, amount=amount, order_type=order_type, pair=pair))

  def query_unsettled_order_list(self):
    return self._query('/api/exchange/orders/opens', params=None)

  def cancel_order(self, order_id):
    return self._query('/api/exchange/orders/%s' % order_id, params=None)

  def query_transaction_history(self):
    return self._query('/api/exchange/orders/transactions', params=None)

  def query_positions_list(self, status):
    return self._query('/api/exchange/leverage/positions', params=dict(status=status))

  def query_balance(self):
    return self._query('/api/accounts/balance', params=None)

  def query_account_information(self):
    return self._query('/api/accounts', params=None)
